/******************************************************************************

  Copyright (C), 2012-2016, ZHANGYA

 ******************************************************************************
  File Name     : uart.c
  Version       : Initial Draft
  Author        : zhangya
  Created       : 2024/4/19
  Last Modified :
  Description   : uart.c
  Function List :
  History       :
  1.Date        : 2024/4/19
    Author      : zhangya
    Modification: Created file

******************************************************************************/
#include "uart.h"

/*--------------------------------------------------------------------*
 * $external variables                           *
 *--------------------------------------------------------------------*/
#define USART_TX_BUF_MAX_SIZE			(512)
#define USART_RX_BUF_MAX_SIZE			(512)

/*--------------------------------------------------------------------*
 * $external routine prototypes                  *
 *--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*
 * $internal routine prototypes                  *
 *--------------------------------------------------------------------*/
static usart_t usart;

static uint8_t uart_tx_buff[USART_TX_BUF_MAX_SIZE + 4] = {0};
static uint8_t uart_rx_buff[USART_RX_BUF_MAX_SIZE + 4] = {0};

/*--------------------------------------------------------------------*
 * $project-wide global variables                *
 *--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*
 * $module-wide global variables                 *
 *--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*
 * $constants                                    *
 *--------------------------------------------------------------------*/

/*--------------------------------------------------------------------*
 * $macros                                       *
 *--------------------------------------------------------------------*/
static void usart_tx_cb(void);
static void usart_rx_finsh_cb(void);
static void usart_rx_cb(uint16_t value);

/*--------------------------------------------------------------------*
 * $routines' implementations                    *
 *--------------------------------------------------------------------*/

/*****************************************************************************
 Prototype    : usart_nvic_init
 Description  : usart nvic init
 Input        : void  
 Output       : None
 Return Value : static
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2023/8/18
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
static void usart_nvic_init(void)
{
	/* config usart nvic interrupt */
	nvic_irq_enable(USART1_IRQn, 1, 1);
}

/*****************************************************************************
 Prototype    : usart_gpio_init
 Description  : usart gpio init
 Input        : void  
 Output       : None
 Return Value : static
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2023/8/18
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
static void usart_gpio_init(void)
{
	crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

	gpio_init_type gpio_init_struct;
	gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
	gpio_init_struct.gpio_out_type  = GPIO_OUTPUT_PUSH_PULL;

	/* configure the usart1 tx pin */
	gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
	gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
	gpio_init_struct.gpio_pins = GPIO_PINS_9;
	gpio_init(GPIOA, &gpio_init_struct);

	/* configure the usart1 rx pin */
	gpio_init_struct.gpio_pull = GPIO_PULL_UP;
	gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
	gpio_init_struct.gpio_pins = GPIO_PINS_10;
	gpio_init(GPIOA, &gpio_init_struct);
}

/*****************************************************************************
 Prototype    : bsp_usart_init
 Description  : bsp usart init
 Input        : void  
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2023/8/18
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
void bsp_usart_init(void)
{
	memset(uart_tx_buff, 0, USART_TX_BUF_MAX_SIZE+4);
	memset(uart_rx_buff, 0, USART_RX_BUF_MAX_SIZE+4);

	usart.send_rng.buf     = uart_tx_buff;
	usart.send_rng.bufSize = USART_TX_BUF_MAX_SIZE;
	usart.send_rng.pFromBuf= 0;
	usart.send_rng.pToBuf  = 0;

	usart.recv_rng.buf     = uart_rx_buff;
	usart.recv_rng.bufSize = USART_RX_BUF_MAX_SIZE;
	usart.recv_rng.pFromBuf= 0;
	usart.recv_rng.pToBuf  = 0;

	usart.send_cb 			= usart_tx_cb;
	usart.recv_finsh_cb 	= usart_rx_finsh_cb;
	usart.recv_cb 			= usart_rx_cb;

	crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);

	usart_gpio_init();
	usart_nvic_init();

	/* configure usart1 param */
	usart_init(USART1, 115200, USART_DATA_8BITS, USART_STOP_1_BIT);
	usart_parity_selection_config(USART1, USART_PARITY_NONE);
	usart_transmitter_enable(USART1, TRUE);
	usart_receiver_enable(USART1, TRUE);

	/* enable usart1 interrupt */
	usart_interrupt_enable(USART1, USART_RDBF_INT, TRUE);
	usart_interrupt_enable(USART1, USART_IDLE_INT, TRUE);
	usart_enable(USART1, TRUE);
}

/*****************************************************************************
 Prototype    : bsp_usart_send
 Description  : bsp usart send
 Input        : int len          
                uint8_t * pData  
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2023/8/18
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
void bsp_usart_send(int len, uint8_t * pData)
{
	int i;
	usart_interrupt_enable(USART1, USART_TDBE_INT, FALSE);
	for (i=0; i<len; i++) {
		while(!(USART1->sts & USART_TDBE_FLAG));
		USART1->dt = (pData[i] & 0x01FF);
	}
	usart_interrupt_enable(USART1, USART_TDBE_INT, TRUE);
}

/*****************************************************************************
 Prototype    : get_usart
 Description  : get usart
 Input        : void  
 Output       : None
 Return Value : usart_t
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2023/8/18
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
usart_t * get_usart(void)
{
	return &usart;
}

/*****************************************************************************
 Prototype    : usart_write
 Description  : usart write
 Input        : int txLen       
                uint8_t * buff  
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2023/8/18
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
void usart_write(int txLen, uint8_t * buff)
{
	s16 len;
	uint8_t value = 0;
	RING_ID rng_id = &(usart.send_rng);
	
	if(txLen <= 0 || buff == NULL)
		return ;

	DEBUG_BUF_U8("tx=", buff, txLen);
	len = rngBufPut(rng_id, (uint8_t *)buff, txLen);

	if(len != txLen)
	{
		rngFlush(rng_id);
		const char * full_str = "buff is full";
		rngBufPut(rng_id, (uint8_t *)full_str, strlen(full_str));
	}

	if(usart.send_state == USART_BUSY)
		return ;

	len = rngBufGetOne(&(usart.send_rng), &value);
	if(len == 0){
		usart.send_state = USART_IDLE;
		usart_interrupt_enable(USART1, USART_TDBE_INT, FALSE);
	   	return ;
	}
	USART1->dt = (value & 0x01FF);
	usart_interrupt_enable(USART1, USART_TDBE_INT, TRUE);
	usart.send_state = USART_BUSY;
}

/*****************************************************************************
 Prototype    : usart_check_rx
 Description  : check rx
 Input        : void  
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/25
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
bool usart_check_rx(void)
{
	if (usart.recv_state == USART_BUSY)
		return false;

	int16_t len = rngNBytes(&usart.recv_rng);
	if (len == 0)
		return false;

	return true;
}

/*****************************************************************************
 Prototype    : usart_read_byte
 Description  : read one byte
 Input        : uint8_t * byte  
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/25
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
bool usart_read_byte(uint8_t * byte)
{
	if (rngBufGetOne(&usart.recv_rng, byte) == 0) {
		return false;
	}
	return true;
}

/*****************************************************************************
 Prototype    : usart_read
 Description  : usart read
 Input        : uint16_t bufSize  
                uint8_t * buf     
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2023/8/18
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
uint16_t usart_read(uint16_t bufSize, uint8_t * buf)
{
	int16_t len;
	RING_ID rng_id = &(usart.recv_rng);

	if (usart.recv_state == USART_BUSY)
		return 0;

	len = rngNBytes(rng_id);
	if (len == 0)
		return 0;

	if (len > bufSize)
		len = bufSize;

	rngBufGet(rng_id, (uint8_t *)buf, len);

	return len;
}

/*****************************************************************************
 Prototype    : usart_rx_buff_clean
 Description  : clean rx buffer
 Input        : void  
 Output       : None
 Return Value : 
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2024/5/25
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
void usart_rx_buff_clean(void)
{
	RING_ID rng_id = &(usart.recv_rng);
	rngFlush(rng_id);
}
/*****************************************************************************
 Prototype    : usart_tx_cb
 Description  : usart tx callback
 Input        : void  
 Output       : None
 Return Value : static
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2023/8/18
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
static void usart_tx_cb(void)
{
	uint8_t len, value;
	RING_ID rng_id = &(usart.send_rng);

	len = rngBufGetOne(rng_id, &value);
	if(len == 0){
		usart.send_state = USART_IDLE;
		usart_interrupt_enable(USART1, USART_TDBE_INT, FALSE);
		return ;
	}
	USART1->dt = (value & 0x01FF);
}

/*****************************************************************************
 Prototype    : usart_rx_finsh_cb
 Description  : usart rx finsh callback
 Input        : void  
 Output       : None
 Return Value : static
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2023/8/18
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
static void usart_rx_finsh_cb(void)
{
	if (usart.recv_state == USART_BUSY)
		usart.recv_state = USART_IDLE;

#if DEBUG_EN > 0
	uint8_t buff[32] = {0};
	int16_t len = 0;
	len = rngBufGetNoDel(&usart.recv_rng, (uint8_t *)buff, 32);
	DEBUG_BUF_U8("uart rx= ", buff, len);
#endif
}

/*****************************************************************************
 Prototype    : usart_rx_cb
 Description  : usart rx callback
 Input        : uint16_t value  
 Output       : None
 Return Value : static
 Calls        : 
 Called By    : 
 
  History        :
  1.Date         : 2023/8/18
    Author       : zhangya
    Modification : Created function

*****************************************************************************/
static void usart_rx_cb(uint16_t value)
{
	RING_ID rng_id = &(usart.recv_rng);

	if (rngIsFull(rng_id))
		return ;

	usart.recv_state = USART_BUSY;
	rngBufPutOne(rng_id, value);
}

